#pragma once

#include "oj_model.hpp"
#include "oj_view.hpp"
//#include "../common/log.hpp"
#include "../RPC/source/common/log.hpp"
#include "../common/util.hpp"

#include <vector>
#include <mutex>
#include <fstream>
#include <memory>
#include <cassert>
#include <algorithm>
#include <jsoncpp/json/json.h>
#include <unordered_set>
#include "../RPC/source/client/rpc_client.hpp"
#include "../RPC/source/common/log.hpp"

// RPC版
namespace oj_control
{
    //using namespace oj_log;
    using namespace oj_util;

    class Control
    {
    public:
        Control()
        {   
            //启用服务发现
            _client = std::make_unique<JsonMuduoRPC::client::RPCClient>(true, "127.0.0.1", 9090);
            assert(_client.get());
        }

        // 获得所有的题目信息，并组织成网页返回
        bool allQuestions(std::string &html)
        {
            std::vector<oj_model::Question> questions;
            if (!_model.getAllQuestions(questions))
            {
                html = "当前没有题目可供获取";
                return false;
            }

            // 对题目根据编号进行正序排序
            std::sort(questions.begin(), questions.end(), [](const oj_model::Question &q1, const oj_model::Question &q2)
                      { return std::stoi(q1.number) < std::stoi(q2.number); });

            // 网页渲染
            _view.allQuestionsExpandHtml(questions, html);

            return true;
        }

        // 获取一个题目的具体信息，并组织成网页返回
        bool question(const std::string &number, std::string &html)
        {
            oj_model::Question question;
            if (!_model.getOneQuestion(number, question))
            {
                html = "不存在题目: " + number;
                return false;
            }

            // 网页渲染
            _view.onQuestionExpandHtml(question, html);

            return true;
        }

        // 判题
        //  in_json: code + input
        bool judge(const std::string &number, const std::string &in_json, std::string &out_json)
        {
            // 1. 获得对应题目的信息
            oj_model::Question question;
            _model.getOneQuestion(number, question);

            // 2. 对输入信息反序列化
            Json::Value in_root;
            if (!JsonMuduoRPC::JSON::unserialize(in_json, in_root))
            {
                LOG(JsonMuduoRPC::ERROR, "输入解析失败");
                return false;
            }

            // 构成RPC请求
            Json::Value seq_root;
            seq_root["input"] = in_root["input"].asString();
            seq_root["code"] = in_root["code"].asString() + "\n" + question.tail; // 代码 + 测试用例 = 完整代码
            seq_root["cpu_limit"] = question.cpu_limit;
            seq_root["mem_limit"] = question.mem_limit;

            //发送RPC调用请求
            Json::Value rsp_root;
            if (!_client->call("compile_run", seq_root, rsp_root))
            {
                LOG(JsonMuduoRPC::ERROR, "RPC调用失败");
                return false;
            }
            LOG(JsonMuduoRPC::INFO, "获取结果成功");

            if(!JsonMuduoRPC::JSON::serialize(rsp_root, out_json))
            {
                LOG(JsonMuduoRPC::ERROR, "输出解析失败");
                return false;
            }

            return true;
        }

    private:
        oj_model::Model _model;
        oj_view::View _view;
        JsonMuduoRPC::client::RPCClient::ptr _client;
    };
}

// namespace oj_control
// {
//     using namespace oj_log;
//     using namespace oj_util;

//     const std::string default_conf_path = "./conf/service_machine.conf";

//     struct Machine
//     {
//         std::string ip;
//         uint16_t port;
//         uint64_t load;
//         std::mutex *mutex;

//         void incLoad()
//         {
//             if (mutex)
//             {
//                 std::unique_lock<std::mutex> lock(*mutex);
//                 ++load;
//             }
//         }

//         void decLoad()
//         {
//             if (mutex)
//             {
//                 std::unique_lock<std::mutex> lock(*mutex);
//                 --load;
//             }
//         }

//         void resetLoad()
//         {
//             if (mutex)
//             {
//                 std::unique_lock<std::mutex> lock(*mutex);
//                 load = 0;
//             }
//         }

//     };

//     class LoadBalance
//     {
//     public:
//         LoadBalance()
//         {
//             assert(loadConf(default_conf_path));
//         }

//         bool smartChoose(int &id, Machine *&machine)
//         {
//             std::unique_lock<std::mutex> lock(_mutex);

//             // 负载均衡算法：选择load最低的主机进行返回
//             if (_online.size() == 0)
//             {
//                 LOG(FATAL, "没有主机可以提供编译运行服务！！！");
//                 return false;
//             }

//             id = *(_online.begin());
//             machine = &_machines[id];
//             int min_load = machine->load;

//             for (auto it : _online)
//             {
//                 if (min_load > _machines[it].load)
//                 {
//                     min_load = _machines[it].load;
//                     id = it;
//                     machine = &_machines[it];
//                 }
//             }

//             return true;
//         }

//         void onlineMachine()
//         {
//             //统一上线所有主机
//             std::unique_lock<std::mutex> lock(_mutex);

//             _online.insert(_offline.begin(), _offline.end());
//             _offline.clear();
//         }

//         // 下线对应id的主机
//         void offlineMachine(int id)
//         {
//             std::unique_lock<std::mutex> lock(_mutex);

//             auto it = _online.find(id);
//             if (it == _online.end())
//                 return;

//             _machines[id].resetLoad();  //将主机下线后，要将其负载清零
//             _online.erase(it);
//             _offline.insert(id);
//         }

//         void debug()
//         {
//             std::unique_lock<std::mutex> lock(_mutex);

//             std::cout << "当前上线的主机: ";
//             for (auto& it : _online)
//                 std::cout << it << " ";
//             std::cout << std::endl;

//             std::cout << "当前离线的主机: ";
//             for (auto& it : _offline)
//                 std::cout << it << " ";
//             std::cout << std::endl;
//         }

//     private:
//         bool loadConf(const std::string &conf_path)
//         {
//             std::ifstream in(conf_path);
//             if (in.is_open() == false)
//             {
//                 LOG(FATAL, "配置文件 %s 加载失败", conf_path.c_str());
//                 return false;
//             }

//             std::string line;
//             while (std::getline(in, line))
//             {
//                 std::vector<std::string> tokens;
//                 StringUtil::spiltStr(line, tokens, " ");

//                 if (tokens.size() != 2)
//                 {
//                     LOG(ERROR, "line %s 加载失败", line);
//                     continue;
//                 }

//                 Machine machine;
//                 machine.ip = tokens[0];
//                 machine.port = std::stoi(tokens[1]);
//                 machine.mutex = new std::mutex();
//                 machine.load = 0;

//                 _online.insert(_machines.size());
//                 _machines.push_back(machine);
//             }

//             LOG(INFO, "配置文件加载成功");
//             in.close();

//             return true;
//         }

//     private:
//         std::mutex _mutex;
//         std::vector<Machine> _machines; // 提供服务的主机，数组下标为主机id
//         std::unordered_set<int> _online;       // 上线的主机id
//         std::unordered_set<int> _offline;      // 下线服务的id
//     };

//     class Control
//     {
//     public:
//         //用于提供给上层，恢复所有主机
//         void recoverMachine()
//         {
//             _load_balance.onlineMachine();
//             LOG(INFO, "所有服务重新上线成功!!!");
//         }

//         // 获得所有的题目信息，并组织成网页返回
//         bool allQuestions(std::string &html)
//         {
//             std::vector<oj_model::Question> questions;
//             if (!_model.getAllQuestions(questions))
//             {
//                 html = "当前没有题目可供获取";
//                 return false;
//             }

//             //对题目根据编号进行正序排序
//             std::sort(questions.begin(), questions.end(), [](const oj_model::Question& q1, const oj_model::Question& q2){
//                 return std::stoi(q1.number) < std::stoi(q2.number);
//             });

//             // 网页渲染
//             _view.allQuestionsExpandHtml(questions, html);

//             return true;
//         }

//         // 获取一个题目的具体信息，并组织成网页返回
//         bool question(const std::string &number, std::string &html)
//         {
//             oj_model::Question question;
//             if (!_model.getOneQuestion(number, question))
//             {
//                 html = "不存在题目: " + number;
//                 return false;
//             }

//             // 网页渲染
//             _view.onQuestionExpandHtml(question, html);

//             return true;
//         }

//         // 判题
//         //  in_json: code + input
//         bool judge(const std::string &number, const std::string &in_json, std::string &out_json)
//         {
//             // 1. 获得对应题目的信息
//             oj_model::Question question;
//             _model.getOneQuestion(number, question);

//             // 2. 对输入信息反序列化
//             Json::Value in_root;
//             Json::CharReaderBuilder reader_builder;
//             std::unique_ptr<Json::CharReader> reader(reader_builder.newCharReader());

//             std::string err;
//             bool ret = reader->parse(in_json.c_str(), in_json.c_str() + in_json.size(), &in_root, &err);
//             if (ret == false)
//             {
//                 std::cout << "in_json: " << in_json << std::endl;
//                 LOG(ERROR, "反序列化失败: %s", err.c_str());
//                 return false;
//             }

//             //构成HTTP请求
//             Json::Value out_root;
//             out_root["input"] = in_root["input"].asString();
//             out_root["code"] = in_root["code"].asString() + "\n" + question.tail; // 代码 + 测试用例 = 完整代码
//             out_root["cpu_limit"] = question.cpu_limit;
//             out_root["mem_limit"] = question.mem_limit;

//             // 3. 将完整代码和限制条件序列化
//             std::string compile_run_json;
//             std::stringstream ss;
//             Json::StreamWriterBuilder writer_builder;
//             // 配置StreamWriterBuilder，使其不进行Unicode转义
//             writer_builder.settings_["emitUTF8"] = true;
//             std::unique_ptr<Json::StreamWriter> writer(writer_builder.newStreamWriter());

//             writer->write(out_root, &ss);

//             compile_run_json = ss.str();

//             // 4. 负载均衡，选择合适的编译运行主机发送HTTP请求
//             int id = 0;
//             Machine *machine;
//             while (true)
//             {
//                 if (_load_balance.smartChoose(id, machine) == false)
//                 {
//                     return false;
//                 }

//                 LOG(INFO, "成功选择主机: id: %d [%s:%d]", id, machine->ip.c_str(), machine->port);
//                 machine->incLoad(); // 增加该主机的负载

//                 httplib::Client client(machine->ip, machine->port);
//                 if (auto res = client.Post("/compile_run", compile_run_json, "application/json;charset=utf-8"))
//                 {
//                     //res就是收到的编译运行服务其的响应
//                     if (res->status == 200)
//                     {
//                         // 将响应结果返回给out_json
//                         out_json = res->body;
//                         LOG(INFO, "请求编译运行服务成功, id: %d [%s:%d]", id, machine->ip.c_str(), machine->port);
//                         machine->decLoad(); //请求处理成功，减少负载
//                         return true;
//                     }
//                     LOG(WARNING, "请求编译运行服务失败, id: %d [%s:%d]", id, machine->ip.c_str(), machine->port);
//                     machine->decLoad();//状态异常，未处理请求，减少负载
//                 }
//                 else
//                 {
//                     LOG(ERROR, "当前请求的主机连接失败: id: %d [%s:%d]", id, machine->ip.c_str(), machine->port);

//                     //如果连接服务器失败，说明该服务可能已经下线，oj_server就要对管理的服务进行下线操作
//                     _load_balance.offlineMachine(id);
//                     _load_balance.debug();      //debug
//                 }
//             }
//         }

//     private:
//         LoadBalance _load_balance;
//         oj_model::Model _model;
//         oj_view::View _view;
//     };
// }